/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INERINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <isa.h>
#define ERING_BUFF_SIZE 128
struct _ERing {
  CSR csr;
} ering_buff[ERING_BUFF_SIZE] = {0};
int ering_buff_index = 0;

void ering_save_fun() {
  ering_buff[ering_buff_index%ERING_BUFF_SIZE].csr = csr;
  ering_buff_index ++;
}
void print_ering_buff(void) {
  printf("ering buff:\n");
  int exception_cnt = ering_buff_index;
  int idx = 0;
  if(exception_cnt > ERING_BUFF_SIZE) {
    exception_cnt = ERING_BUFF_SIZE;
    idx = ering_buff_index;
  }
  while (exception_cnt--)
  {
    struct _ERing ering = ering_buff[idx%ERING_BUFF_SIZE];
    printf("\tcsr: mepc: " FMT_WORD " mcause:" FMT_WORD "\n",ering.csr.mepc,ering.csr.mcause);
    idx++;
  }
  
}
word_t isa_raise_intr(word_t NO, vaddr_t epc) {
  /* TODO: Trigger an interrupt/exception with ``NO''.
   * Then return the address of the interrupt/exception vector.
   */
  // if(NO != MCAUSE_ECALL_M)
  // printf("isa_raise_intr: NO:%ld epc:" FMT_WORD "\n",NO,epc);
  csr_write(MEPC_ADDR,epc);
  csr_write(MCAUSE_ADDR,NO);
  word_t mie;
  mie = csr_read(MSTATUS_ADDR)&MSATUS_MIE_MASK;
  // Log("MIE:%ld",mie);

  if(mie) csr_set_bits(MSTATUS_ADDR,MSATUS_MPIE_MASK);
  else csr_clear_bits(MSTATUS_ADDR,MSATUS_MPIE_MASK);
  // Log("MPIE:%ld",csr_read(MSTATUS_ADDR)&MSATUS_MPIE_MASK);
  csr_clear_bits(MSTATUS_ADDR,MSATUS_MIE_MASK);

  ering_save_fun();
  // printf("TVEC:0x%08lx\n",csr_read(MTVEC_ADDR));
  return csr_read(MTVEC_ADDR);
}

word_t isa_query_intr() {
  return INTR_EMPTY;
}
